package cn.lan.code.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.lan.code.utils.ConstantUtil;
import cn.lan.code.utils.ValidateException;
import cn.lan.code.vo.ProjectParam;
import cn.lan.code.vo.Response;
import cn.lan.generator.bean.Connector;
import cn.lan.generator.bean.ProjInfo;
import cn.lan.generator.bean.TableEntity;
import cn.lan.generator.bean.TableInfo;
import cn.lan.generator.factory.ProjectManagerFactory;
import cn.lan.generator.factory.TableInfoFactory;
import cn.lan.generator.manager.AbstractProjectManager;
import cn.lan.generator.utils.ConfigUtil;
import cn.lan.generator.utils.Constant;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.http.MediaType;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;

/**
 * 小程序用户
 * 
 * @author lanping
 * @version 1.0
 * @date 2021-08-14
 */
@Api(tags="代码自动化")
@RequestMapping(value = "/v1/")
@RestController
public class ProjectController extends BaseController {

	@ApiOperation(value="创建项目")
	@PostMapping(value = "/createProject", produces = MediaType.APPLICATION_JSON_VALUE)
	public Response createCoder(@RequestBody ProjectParam projectParam,
								HttpServletRequest request, HttpServletResponse response) throws Exception {

		ProjInfo projInfo = getInitProject();
		BeanUtil.copyProperties(projectParam,projInfo);
		projInfo.setThymeleaf(ConstantUtil.IS_VALID_Y.equals(projectParam.getCreateHtmlPage()));

		Connector connector = new Connector();
		BeanUtil.copyProperties(projectParam,connector);

		AbstractProjectManager projectManager = ProjectManagerFactory.getProjectManager(connector.getDbType());
		projectManager.createFiles(connector,projInfo);
		return Response.success(ConstantUtil.MSG_CREATE_SUCCESS);
	}

	@ApiOperation(value="创建单表代码")
	@PostMapping(value = "/createCoderByTables", produces = MediaType.APPLICATION_JSON_VALUE)
	public Response createCoderBYTables(@RequestBody ProjectParam projectParam,
								HttpServletRequest request, HttpServletResponse response) throws Exception {

		if(ObjectUtil.isEmpty(projectParam.getTableNames())){
			throw new ValidateException("表名不能为空");
		}
		TableEntity tableEntity = new TableEntity();
		tableEntity.setTableNames(projectParam.getTableNames().toArray(new String[0]));

		ProjInfo projInfo = getInitProject();
		BeanUtil.copyProperties(projectParam,projInfo);
		projInfo.setThymeleaf(ConstantUtil.IS_VALID_Y.equals(projectParam.getCreateHtmlPage()));

		Connector connector = new Connector();
		BeanUtil.copyProperties(projectParam,connector);

		AbstractProjectManager projectManager = ProjectManagerFactory.getProjectManager(connector.getDbType());
		projectManager.createFilesByTables(connector,projInfo, tableEntity);
		return Response.success(ConstantUtil.MSG_CREATE_SUCCESS);
	}

	/**
	 * 获取project
	 * @return
	 */
	private ProjInfo getInitProject(){
		ProjInfo projInfo = new ProjInfo();
		projInfo.setCreateProjectUrl(ConfigUtil.getConfigValue(Constant.KEY_CREATE_PROJ_URL));
		projInfo.setCreateZIPFile(true);
		projInfo.setDebugModel(false);
		projInfo.setModuleName("user");
		projInfo.setCreateModulePomXml(true);
		return projInfo;
	}

	@ApiOperation(value="查询数据库所有表")
	@PostMapping(value = "/tables", produces = MediaType.APPLICATION_JSON_VALUE)
	public Response tables(@RequestBody Connector connector,
								HttpServletRequest request, HttpServletResponse response) throws Exception {
		List<TableInfo> tableInfos = TableInfoFactory.getTableService(connector.getDbType()).selectTables(connector);
		return Response.data(tableInfos);
	}

	//下载文件 读取服务器文件
	@ApiImplicitParams({
			@ApiImplicitParam(name = "filePath", value = "文件路径（可多层目录）", dataType = "String", paramType = "path", required = false)
	})
	@ApiOperation(value = "下载文件")
	@GetMapping(value = "/download/{filePath}/**")
	public void downloadFile(@PathVariable String filePath, HttpServletRequest request,
							 HttpServletResponse response) throws Exception {

		String rootDir = ConfigUtil.getConfigValue(Constant.KEY_CREATE_PROJ_URL);
		String path = rootDir + filePath;

		String fileName = extractPathFromPattern(request);
		if (StrUtil.isNotBlank(fileName)) {
			path += File.separator + fileName;
		}

		// 通过文件路径获得File对象
		File file = new File(path);
		if (!file.exists()) {
			if (!file.exists()) {
				String data = "<script>alert('文件不存在');</script>";
				output(response, data, "text/html;charset=UTF-8");
				return;
			}
		}

		downloadFile(response,file,file.getName(),true);
	}


	/**
	 * 下载文件
	 * @param response
	 * @param file
	 * @throws IOException
	 */
	public static void downloadFile(HttpServletResponse response, File file, String fileName, boolean isDel) throws IOException {
		//下载文件
		fileName = StrUtil.isBlank(fileName)?file.getName():fileName;
		InputStream fis = new BufferedInputStream(new FileInputStream(file));
		byte[] buffer = new byte[fis.available()];
		int length = -1;
		response.addHeader(
				"Content-Disposition",
				"attachment;filename=\"" + new String(fileName.getBytes("utf-8"), "iso8859-1")+"\"");
		response.addHeader("Content-Length", "" + file.length());
		response.setContentType("application/octet-stream");
		OutputStream os = new BufferedOutputStream(
				response.getOutputStream());
		while ((length = fis.read(buffer)) != -1) {
			os.write(buffer, 0, length);
		}
		os.flush();
		fis.close();
		os.close();

		if(isDel){
			file.delete();
		}
	}

	private String extractPathFromPattern(final HttpServletRequest request) {
		String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
		String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
		return new AntPathMatcher().extractPathWithinPattern(bestMatchPattern, path);
	}
}
